﻿#include "ui_MaterialEditWidget.h"
#include "MaterialEditWidget.h"
#include "MaterialDescriptionEditWidget.h"
#include "MaterialWidgetBase.h"
#include "MaterialDensityWidget.h"
#include "MaterialElasticWidget.h"
#include "MaterialHyperelasticWidget.h"
#include "MaterialPlasticWidget.h"
#include "MaterialExpamsionWidget.h"
#include "MaterialJohnsonCookDamageWidget.h"
#include "MaterialDampingWidget.h"
#include "GUIFrame/MainWindow.h"
#include "GUIWidget/GUIDialogManager.h"
#include "OperatorsInterface/ParaWidgetInterfaceOperator.h"
#include "FITK_Kernel/FITKCore/FITKOperatorRepo.h"
#include "FITK_Kernel/FITKCore/FITKActionOperator.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Interface/FITKInterfacePhysics/FITKAbstractMaterial.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMaterial.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMaterialDensity.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMaterialElastic.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMaterialPlastic.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMaterialJohnsonCookDamage.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMaterialDamping.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMaterialExpansion.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMaterialHyperElastic.h"
#include <QMenuBar>
#include <QMessageBox>
#include <QWidget>

#include "GUIFrame/PropertyWidget.h"
#define ITEM_TYPE_PROPERTY "MaterialItemType"


#define SetupType Interface::FITKOFSolverTypeEnum::FITKOFSolverFiltersType
namespace GUI
{
    MaterialEditWidget::MaterialEditWidget(Interface::FITKAbaMaterial* material,EventOper::ParaWidgetInterfaceOperator* oper, QWidget* parent) :
        MaterialWidgetBase(oper,parent),_material(material)
    {
        _ui = new Ui::MaterialEditWidget();
        _ui->setupUi(this);

        connect(_ui->toolButtonDelete, SIGNAL(clicked()),
            this, SLOT(onDeleteItemClicked()));

        connect(_ui->materialBehaviorsList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
            this, SLOT(currentItemChanged(QListWidgetItem*, QListWidgetItem*)));

        //auto abaqusData = AbaqusData::FITKAbaqusData::GetDataFromAppFrame();

        //_manager = abaqusData->getCurrentCase()->getMaterialManager();

        _manager = FITKAPP->getGlobalData()->getMaterialData<Interface::FITKMaterialManager>();

        _tmpMaterial = new Interface::FITKAbaMaterial();

        //int count = _material->getMaterialID();//材料的个数

        //判断材料是创建还是编辑
        if (_material == nullptr) {
            QString name = QString("Material-%1").arg(_manager->getDataCount() + 1);
            _tmpMaterial->setDataObjectName(name);
            this->setWindowTitle(QObject::tr("Create Material"));
        }
        else {
            _tmpMaterial->copy(_material);
            _tmpMaterial->setDataObjectName(_material->getDataObjectName());
            _ui->materialNameLine->setEnabled(false);
            setWindowTitle(tr("Edit Material"));
            //添加描述信息
            QString description = _material->getMaterialDescribe();
            _ui->materialDescriptionText->document()->setPlainText(description);
        }

        //初始化对话框
        initDialog();
    }

    MaterialEditWidget::~MaterialEditWidget()
    {
        if (!_ui)delete _ui; _ui = nullptr;
        if (!_tmpMaterial)delete _tmpMaterial; _tmpMaterial = nullptr;

        _formWidgetHash.clear();
    }

    void MaterialEditWidget::on_buttonOK_clicked()
    {
        QString name = _ui->materialNameLine->text();
        // 检查名字合法
        bool isCreate = (_material == nullptr);
        if (name.isEmpty() || (isCreate && _manager->getDataByName(name)))
        {
            QMessageBox::information(this, QObject::tr("Warning"), QObject::tr("Name illegal"));
            return;
        }
        _tmpMaterial->setDataObjectName(name);

        if (!checkValue()) return;

        if (_material == nullptr)  // 创建操作
        {
            _material = new Interface::FITKAbaMaterial();
            _manager->appendDataObj(_material);
        }

        // 将编辑过的数据复制回工程数据中
        _material->copy(_tmpMaterial);
        _material->setDataObjectName(_ui->materialNameLine->text());

        //添加描述信息
        QString description = _ui->materialDescriptionText->document()->toPlainText();
        _material->setMaterialDescribe(description);
        
        if (_oper != nullptr) {
            //执行操作器
            _oper->execProfession();
        }

        GUI::MainWindow* mainWindow = dynamic_cast<GUI::MainWindow*>(FITKAPP->getGlobalData()->getMainWindow());
        if (mainWindow == nullptr)return;
        GUI::PropertyWidget* propertyWidget = mainWindow->getPropertyWidget();
        if (propertyWidget == nullptr)return;

        propertyWidget->init();

    }

    void MaterialEditWidget::on_buttnCancel_clicked()
    {
        GUI::MainWindow* mainWindow = dynamic_cast<GUI::MainWindow*>(FITKAPP->getGlobalData()->getMainWindow());
        if (mainWindow == nullptr)return;
        GUI::PropertyWidget* propertyWidget = mainWindow->getPropertyWidget();
        if (propertyWidget == nullptr)return;

        propertyWidget->init();

    }

    void MaterialEditWidget::onEditMaterialItem(QAction * action)
    {
        if (action == nullptr) return;
        int type = action->property("MaterialItemType").value< int >();
        Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType itemType =
            Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType(type);
        if (_currentItemType == itemType)
        {
            return;
        }

        if (!findMaterialItem(itemType))
        {
            _tmpMaterial->addMaterialBehavior(itemType);
            updateListWidget();
        }
        showItemForm(itemType);
    }

    void MaterialEditWidget::currentItemChanged(QListWidgetItem * current, QListWidgetItem * previous)
    {
        if (current == nullptr) return;
        int a = current->data(CASEIDROLE).value< int >();
        Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType type =
            Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType(a);

        if (_currentItemType == type)
        {
            return;
        }
        showItemForm(type);
    }

    void MaterialEditWidget::onDeleteItemClicked()
    {
        auto listItem = _ui->materialBehaviorsList->currentItem();
        if (listItem == nullptr) return;

        int data = listItem->data(CASEIDROLE).toInt();
        Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType type =
            Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType(data);

        // 删除选项子窗体并更新
        {
            Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType lastType;
            int currentRow = _ui->materialBehaviorsList->row(listItem);
            if (currentRow > 0) {
                QListWidgetItem* lastItem = _ui->materialBehaviorsList->item(currentRow - 1);
                if (lastItem != nullptr) {
                    lastType = Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType(lastItem->data(CASEIDROLE).toInt());
                    lastItem->setSelected(true);
                }
            }
            else if(currentRow == 0 && _formWidgetHash.size() > 1) {
                QListWidgetItem* lastItem = _ui->materialBehaviorsList->item(currentRow + 1);
                if (lastItem != nullptr) {
                    lastType = Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType(lastItem->data(CASEIDROLE).toInt());
                    lastItem->setSelected(true);
                }
            }
            _formWidgetHash.remove(type);

            // 删除选项子窗体
            QLayoutItem* child = _ui->frameOptions->layout()->takeAt(currentRow);
            if (child != nullptr)
            {
                delete (child->widget());
                delete child;
            }

            //重新设置一个界面
            showItemForm(lastType);
        }

        // 删除数据项
        if (_tmpMaterial == nullptr) return;
        auto matBea = _tmpMaterial->getMaterialBeahviors();
        for (int i = 0; i < matBea.count(); i++)
        {
            auto tmpItem = matBea[i];
            if (tmpItem == nullptr) continue;
            if (type == tmpItem->getMaterialBehaviorType())
            {
                _tmpMaterial->removeMaterialBehavior(type);
                break;
            }
        }

        // 更新列表
        updateListWidget();
    }

    void MaterialEditWidget::on_pb_editdesc_clicked()
    {
        MainWindow* mainWindow = nullptr;
        mainWindow = dynamic_cast<MainWindow*>(FITKAPP->getGlobalData()->getMainWindow());
        MaterialDescriptionEditWidget* dlg =
            new MaterialDescriptionEditWidget(mainWindow, _ui->materialNameLine->text(), _ui->materialDescriptionText->document()->toPlainText());

        if (QDialog::Accepted) {
            QString message = dlg->getDescText();
            _ui->materialDescriptionText->setPlainText(message);
        }
        dlg->deleteLater();
    }

    void MaterialEditWidget::initDialog()
    {
        if (_tmpMaterial == nullptr) return;
        QString name = _tmpMaterial->getDataObjectName();
        _ui->materialNameLine->setText(name);

        updateListWidget();
        initMenu();
        QVBoxLayout* vboxOption = new QVBoxLayout();
        vboxOption->setContentsMargins(0, 0, 0, 0);
        _ui->frameOptions->setLayout(vboxOption);

        auto matBeaList = _tmpMaterial->getMaterialBeahviors();
        if (matBeaList.size() != 0)
        {
            //编辑时循环让所有的材料参数界面创建出来，不然在界面编辑且为点击其他界面，其他界面未创建
            //存储数据与数据检查，会出现问题
            for (int i = 0; i < matBeaList.size(); i++) {
                auto metItem = matBeaList[i];
                if (metItem == nullptr) return;
                showItemForm(metItem->getMaterialBehaviorType());
            }

            //设置0号界面为初始显示界面
            auto metItem = matBeaList[0];
            if (metItem == nullptr) return;
            showItemForm(metItem->getMaterialBehaviorType());
        }
    }

    void MaterialEditWidget::updateListWidget()
    {
        if (_tmpMaterial == nullptr) return;
        _ui->materialBehaviorsList->clear();
        auto matBea = _tmpMaterial->getMaterialBeahviors();
        for (int i = 0; i < matBea.count(); i++)
        {
            auto  matItem = matBea[i];
            Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType type = matItem->getMaterialBehaviorType();
            QString str = enumToString(type);
            QListWidgetItem*  listItem = new QListWidgetItem(str);
            listItem->setData(CASEIDROLE, static_cast<int>(type));
            _ui->materialBehaviorsList->addItem(listItem);
        }
    }

    void MaterialEditWidget::initMenu()
    {
        QVBoxLayout* vbox = new QVBoxLayout();
        vbox->setContentsMargins(0, 0, 0, 0);
        _ui->widgetMenu->setLayout(vbox);
        QMenuBar* menuBar = new QMenuBar(this);
        vbox->addWidget(menuBar);

        initGeneralMenu(menuBar);
        initMechanialMenu(menuBar);
    }

    bool MaterialEditWidget::checkValue()
    {
        //检查所有数据
        for (auto widget : _formWidgetHash.values()) {
            if (!widget->checkValue())return false;
        }

        //存储所有数据
        for (auto widget : _formWidgetHash.values()) {
            if (!widget->saveValue())return false;
        }

        return true;
    }

    bool MaterialEditWidget::saveValue()
    {
        return true;
    }
    void MaterialEditWidget::showItemForm(Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType type)
    {
        if (_currentItemType == type) return;

        _currentItemType = type;
        // 将当前类型的materialitem在listWidget中找到并选择为当前项
        Interface::FITKAbaMaterialBehavior* matItem = nullptr;
        for (int i = 0; i < _ui->materialBehaviorsList->count(); i++)
        {
            auto listItem = _ui->materialBehaviorsList->item(i);
            auto data = listItem->data(CASEIDROLE);
            if (data.value< int >() == static_cast<int>(type))
            {
                _ui->materialBehaviorsList->setCurrentRow(i);
                matItem = _tmpMaterial->getMaterialBehavior(type);
                break;
            }
        }

        for (auto w : _formWidgetHash.values()) {
            if(w == nullptr)continue;
            //QString type = _formWidgetHash.key(w);
            w->setVisible(false);
        }

        //判断点击的材料行为
        switch (type)
        {
        case Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Density:
        {
            QWidget* widget = _formWidgetHash.value(type);
            if (widget == nullptr) {
                Interface::FITKAbaMaterialDensity* densityItem = dynamic_cast<Interface::FITKAbaMaterialDensity*>(matItem);
                MaterialDensityWidget* form = new MaterialDensityWidget(_oper,densityItem, this);
                _ui->frameOptions->layout()->addWidget(form);
                _formWidgetHash.insert(type, form);
            }
            else{
                widget->setVisible(true);
            }
            break;
        }
        case Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Elastic:
        {
            QWidget* widget = _formWidgetHash.value(type);
            if (widget == nullptr) {
                Interface::FITKAbaMaterialElastic* elasticItem = dynamic_cast<Interface::FITKAbaMaterialElastic*>(matItem);
                MaterialElasticWidget* form = new MaterialElasticWidget(_oper,elasticItem, this);
                _ui->frameOptions->layout()->addWidget(form);
                _formWidgetHash.insert(type, form);
            }
            else {
                widget->setVisible(true);
            }
            break;
        }
        case Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Plastic:
        {
            QWidget* widget = _formWidgetHash.value(type);
            if (widget == nullptr) {
                Interface::FITKAbaMaterialPlastic* plasticItem = dynamic_cast<Interface::FITKAbaMaterialPlastic*>(matItem);
                MaterialPlasticWidget* form = new MaterialPlasticWidget(_oper,plasticItem, this);
                _ui->frameOptions->layout()->addWidget(form);
                _formWidgetHash.insert(type, form);
            }
            else {
                widget->setVisible(true);
            }
            break;
        }
        case Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Expansion:
        {
            QWidget* widget = _formWidgetHash.value(type);
            if (widget == nullptr) {
                Interface::FITKAbaMaterialExpansion* plasticItem = dynamic_cast<Interface::FITKAbaMaterialExpansion*>(matItem);
                MaterialExpamsionWidget* form = new MaterialExpamsionWidget(_oper,plasticItem, this);
                _ui->frameOptions->layout()->addWidget(form);
                _formWidgetHash.insert(type, form);
            }
            else {
                widget->setVisible(true);
            }
            break;
        }
        case Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Hyperelastic:
        {
            QWidget* widget = _formWidgetHash.value(type);
            if (widget == nullptr) {
                Interface::FITKAbaMaterialHyperElastic* item = dynamic_cast<Interface::FITKAbaMaterialHyperElastic*>(matItem);
                MaterialHyperelasticWidget* form = new MaterialHyperelasticWidget(_oper,item, this);
                _ui->frameOptions->layout()->addWidget(form);
                _formWidgetHash.insert(type, form);
            }
            else {
                widget->setVisible(true);
            }
            break;
        }
        case Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Damping:
        {
            QWidget* widget = _formWidgetHash.value(type);
            if (widget == nullptr) {
                Interface::FITKAbaMaterialDamping* plasticItem = dynamic_cast<Interface::FITKAbaMaterialDamping*>(matItem);
                MaterialDampingWidget* form = new MaterialDampingWidget(_oper,plasticItem, this);
                _ui->frameOptions->layout()->addWidget(form);
                _formWidgetHash.insert(type, form);
            }
            else {
                widget->setVisible(true);
            }
            break;
        }
        case Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::JohnsonCookDamage:
        {
            QWidget* widget = _formWidgetHash.value(type);
            if (widget == nullptr) {
                Interface::FITKAbaMaterialJohnsonCookDamage* plasticItem = dynamic_cast<Interface::FITKAbaMaterialJohnsonCookDamage*>(matItem);
                MaterialJohnsonCookDamageWidget* form = new MaterialJohnsonCookDamageWidget(_oper,plasticItem, this);
                _ui->frameOptions->layout()->addWidget(form);
                _formWidgetHash.insert(type, form);
            }
            else {
                widget->setVisible(true);
            }
            break;
        }
        }
    }

    Interface::FITKAbaMaterialBehavior * MaterialEditWidget::findMaterialItem(Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType type)
    {
        if (_tmpMaterial == nullptr) return nullptr;

        //遍历所有的材料行为，获取相同行为的数据对象
        for (int i = 0; i < _tmpMaterial->getMaterialBeahviors().count(); i++)
        {
            Interface::FITKAbaMaterialBehavior* item = _tmpMaterial->getMaterialBeahviors()[i];
            if (item == nullptr) continue;
            if (item->getMaterialBehaviorType() == type)
            {
                return item;
            }
        }
        return nullptr;
    }

    QString MaterialEditWidget::enumToString(Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType type)
    {
        QString result = "";
        switch (type) {
        case Interface::FITKAbaMaterialBehaviorEnum::Density:result = tr("Density"); break;
        case Interface::FITKAbaMaterialBehaviorEnum::Elastic:result = tr("Elastic"); break;
        case Interface::FITKAbaMaterialBehaviorEnum::Plastic:result = tr("Plastic"); break;
        case Interface::FITKAbaMaterialBehaviorEnum::Expansion:result = tr("Expansion"); break;
        case Interface::FITKAbaMaterialBehaviorEnum::Hyperelastic:result = tr("Hyperelastic"); break;
        case Interface::FITKAbaMaterialBehaviorEnum::Damping:result = tr("Damping"); break;
        case Interface::FITKAbaMaterialBehaviorEnum::JohnsonCookDamage:result = tr("Johnson-Cook Damage"); break;
        }
        return result;
    }

    void MaterialEditWidget::initGeneralMenu(QMenuBar* menuBar)
    {
        QMenu* GeneralMenu = menuBar->addMenu(tr("General"));
        //密度按钮
        QAction* DensityAction = new QAction(tr("Density"), this);
        DensityAction->setProperty(ITEM_TYPE_PROPERTY, Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Density);
        GeneralMenu->addAction(DensityAction);

        connect(GeneralMenu, SIGNAL(triggered(QAction*)), this, SLOT(onEditMaterialItem(QAction*)));
    }

    void MaterialEditWidget::initMechanialMenu(QMenuBar* menuBar)
    {
        QMenu* mechanialMenu = menuBar->addMenu(tr("Mechanial"));
        //弹性
        {
            QAction* ElasticityAction = new QAction(tr("Elasticity"), this);
            mechanialMenu->addAction(ElasticityAction);

            QMenu* ElasticityMenu = new QMenu(this);
            //弹性按钮
            QAction* ElasticAction = new QAction(tr("Elastic"), this);
            ElasticAction->setProperty(ITEM_TYPE_PROPERTY, Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Elastic);
            ElasticityMenu->addAction(ElasticAction);
            //超弹性按钮
            QAction* HyperelasticAction = new QAction(tr("Hyperelastic"), this);
            HyperelasticAction->setProperty(ITEM_TYPE_PROPERTY, Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Hyperelastic);
            ElasticityMenu->addAction(HyperelasticAction);

            ElasticityAction->setMenu(ElasticityMenu);
        }
        //塑性
        {
            QAction* PlasticityAction = new QAction(tr("Plasticity"), this);
            mechanialMenu->addAction(PlasticityAction);
            
            QMenu* PlasticityMenu = new QMenu(this);
            //塑性按钮
            QAction* plastic = new QAction(tr("Plastic"), this);
            plastic->setProperty(ITEM_TYPE_PROPERTY, Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Plastic);
            PlasticityMenu->addAction(plastic);

            PlasticityAction->setMenu(PlasticityMenu);
        }
        //损伤
        {
            QAction* DamageForDuctileMetalsAction = new QAction(tr("Damage for Ductile Metals"), this);
            mechanialMenu->addAction(DamageForDuctileMetalsAction);
            
            QMenu* DamageForDuctileMetalsMenu = new QMenu(this);
            
            //材料损伤添加
            QAction* JohnsonCookDamageAction = new QAction(tr("Johnson-Cook Damage"), this);
            JohnsonCookDamageAction->setProperty(ITEM_TYPE_PROPERTY, Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::JohnsonCookDamage);
            DamageForDuctileMetalsMenu->addAction(JohnsonCookDamageAction);

            DamageForDuctileMetalsAction->setMenu(DamageForDuctileMetalsMenu);
        }

        //阻尼
        QAction* DampingAction = new QAction(tr("Damping"), this);
        DampingAction->setProperty(ITEM_TYPE_PROPERTY, Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Damping);
        mechanialMenu->addAction(DampingAction);

        //膨胀
        QAction* ExpansionAction = new QAction(tr("Expansion"), this);
        ExpansionAction->setProperty(ITEM_TYPE_PROPERTY, Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Expansion);
        mechanialMenu->addAction(ExpansionAction);

        connect(mechanialMenu, SIGNAL(triggered(QAction*)), this, SLOT(onEditMaterialItem(QAction*)));
    }
}
